package tul.cot.util;

import java.util.Iterator;
import java.util.List;

import tul.cot.MigStats;
import tul.cot.MigrationTree;


/**
 * Global tree statistics. Implements {@link Iterable} interface so it
 * is easy to iterate through all time segments.
 */
public class TreeStats implements Iterable<MigStats> {

	/**
	 * Internal iterator over {@link MigStats}.
	 */
	private class StatsIterator implements Iterator<MigStats> {

		@Override
		public boolean hasNext() {
			return currSegNum < SEG_NUM;
		}

		@Override
		public MigStats next() {
			
			++currSegNum;
			
			if (currSegNum == 0) {
				curr = 0;
				lines = 1;
				
				maxT = tree.getTime();
				minT = START_TIME;
			} else {
				maxT = minT;
				minT = maxT - SEG_LENGTH;
			}
			
			MigStats stats = new MigStats(currSegNum, maxT, minT);
			
			stats.in = lines;
			stats.out = lines;
			
			while (getCurrNode() != null && getCurrNode().getTime() > stats.tMax) {
				++curr;
			}
			
			while (getCurrNode() != null && getCurrNode().getTime() <= stats.tMax && getCurrNode().getTime() > stats.tMin) {
				
				MigrationTree node = getCurrNode();
				
				stats.out += node.getNumSons() - 1;
				stats.splits++;
				
				if (node.getParent() == null) {
					stats.firstSplits++;
				} else if (node.getParent().getTime() > stats.tMax) {
					stats.firstSplits++;
				}
				
				for (MigrationTree son: node.getSons()) {
					String from	= node.getLabel();
					String to	= son.getLabel();
					if (!from.equals(to)) {
						stats.changes++;
						stats.incChangeNum(from, to, 1);
					} else {
						stats.no_changes++;
					}
				}
				
				++curr;
			}
			
			lines = stats.out;
			
			return stats;
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException("remove not implemented");
		}
		
	}
	
	private MigrationTree tree;
	private final double START_TIME;
	private final int SEG_NUM;
	private final double SEG_LENGTH; 
	
	private List<MigrationTree> sortNodes;
	private Iterator<MigStats> iterator;
	
	private double maxT;
	private double minT;
	private int currSegNum;
	private int curr;
	private int lines;
	
	public TreeStats(MigrationTree tree, double startTime, int segNum) {
		this.tree = tree;
		this.START_TIME = startTime;
		this.SEG_NUM = segNum;
		this.SEG_LENGTH = START_TIME / SEG_NUM;
		
		init();
	}
	
	private void init() {
		sortNodes = TreeUtils.sortNodes(tree);
		
		//TODO
		currSegNum = -1;
		iterator = new StatsIterator();
	}

	@Override
	public Iterator<MigStats> iterator() {
		return iterator;
	}
	
	private MigrationTree getCurrNode() {
		return curr < sortNodes.size() ? sortNodes.get(curr) : null;
	}
	
	
}
